#include "balloc.h"
#include <memory>

using namespace lm1;

char* BAlloc::freepoolstart = nullptr;
char* BAlloc::freepoolend = nullptr;
int BAlloc::lastmallocsize = 0;
BAlloc::obj* BAlloc::blockheads[16] = {nullptr};
const size_t BAlloc::blocksize[16] = {8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 88, 96, 104, 112, 120, 128};

#define ONCEBLKSIZE 20


BAlloc::BAlloc()
{

}

void *BAlloc::allocator(size_t size)
{
	if (size == 0)
		return nullptr;

	if (size > 128)
		return malloc(size);

	size_t nIndex = getHeadIndex(size);
	if (blockheads[nIndex] == nullptr)
	{
		size_t szBlksize = blocksize[nIndex];
		size_t szFree = freepoolend - freepoolstart;
		if (szFree > szBlksize)
		{
			size_t szCount = szFree / szBlksize;
			union obj* p;
			blockheads[nIndex] = p = (union obj*)(freepoolstart + szBlksize);
			for (size_t i = 0; i < szCount - 1; i++)
			{
				p->next = (union obj*)((char*)p + szBlksize);
				p = p->next;
			}
			p->next = nullptr;
			p = (union obj*)freepoolstart;
			freepoolstart = freepoolstart + szCount * szBlksize;
			return p;
		}
		else if (szFree != 0 && szFree < szBlksize)
		{
			size_t nFreeIndex = getHeadIndex(szFree);
			union obj* pFreeIndexHead = blockheads[nFreeIndex];
			union obj* p = static_cast<union obj*>((void*)freepoolstart);
			p->next = pFreeIndexHead;
			pFreeIndexHead = p;
			freepoolstart = freepoolend;
		}


		size_t nMallocSize = szBlksize * ONCEBLKSIZE + Round_up(lastmallocsize >> 4);
		void *mem = ::malloc(nMallocSize);
		union obj *p;
		union obj *pHead = blockheads[nIndex];
		pHead = p = (union obj*)mem;
		freepoolend = (char*)((char*)p + nMallocSize);
		for (int var = 0; var < ONCEBLKSIZE - 1; ++var)
		{
			p->next = (union obj*)((char*)p + szBlksize);
			p = p->next;
		}
		p->next = nullptr;
		freepoolstart = (char*)((char*)p + szBlksize);
		p = pHead;
		pHead = pHead->next;
		lastmallocsize += nMallocSize;
		return p;
	}

	union obj* pHead = blockheads[nIndex];
	union obj* p = pHead;
	pHead = p->next;
	return p;
}

void BAlloc::deallocator(void *ptr, size_t size)
{
	size_t szIndex = getHeadIndex(size);
	union obj* pObj = static_cast<union obj*>(ptr);
	pObj->next = blockheads[szIndex];
	blockheads[szIndex] = pObj;
}

size_t BAlloc::Round_up(size_t nSize)
{
	size_t ndiv = nSize / 8;
	size_t nmod = nSize % 8;
	if (nmod > 0)
		return (ndiv - 1) * 8;
	return nSize;
}

size_t BAlloc::getHeadIndex(size_t nSize)
{
	size_t nDiv = nSize / 8;
	size_t nMod = nSize % 8;
	if (nDiv == 0)
		nDiv ++;
	else if (nDiv > 0 && nMod > 0)
		nDiv ++;
	return nDiv;
}
